use chrono::Local;
use std::fs::read_to_string;
use std::process::Command;

pub const INTERVAL:u64 = 1;

pub fn spawn(cmd: Option<&str>) -> Option<String> {
    if let Some(cmd) = cmd {
        if let  Ok(output) = Command::new("sh").arg("-c").arg(cmd).output(){
            let mut output=output.stdout;
            output.pop();
            Some(String::from_utf8(output).unwrap())
        }else{
            None
        }
    } else {
        None
    }
}

pub fn cmd(cmd: Option<&str>) -> Option<String> {
    if let Some(cmd) = cmd {
        Command::new("/bin/sh")
            .arg("-c")
            .arg(cmd)
            .output()
            .expect("failed to execute process");
    };
    None
}

pub fn get_time(_: Option<&str>) -> Option<String> {
    Some(Local::now().format("%Y-%m-%d %H:%M").to_string())
}

pub fn get_bat_capacity(_: Option<&str>) -> Option<String> {
    if let Ok(bat) = read_to_string("/sys/class/power_supply/BAT0/capacity"){
        Some(bat.trim().to_string())
    }else{
        None
    }
}

pub fn get_bat_status(_: Option<&str>) -> Option<String> {
    if let  Ok(stauts) = read_to_string("/sys/class/power_supply/BAT0/status"){
        Some(
            if stauts.trim() == "Discharging"{ "🔋" } else { "🔌" }.to_string()
        )
    }else{
        None
    }
}

pub fn get_mem_available(_: Option<&str>) -> Option<String> {
    if let Ok(meminfo) = read_to_string("/proc/meminfo"){
        let mem = meminfo.lines().find_map(|line|{
            let mut spl = line.split_whitespace();
            if  spl.next() == Some("MemAvailable:"){
                spl.next().unwrap().parse::<u64>().ok()
            }else{
                None
            }
        });
        if let Some(mem) = mem{
            Some(if mem > 1024 {
                format!("{}M",mem >> 10)
            }else{
                format!("{}K",mem)
            })
        }else{
            None
        }
    }else{
        None
    }
}

pub fn get_vol(_: Option<&str>) -> Option<String> {
    let status = spawn(Some(
        // r#"amixer sget Master | tail -n1 | sed -r "s/.*\[(.*)\]/\1/""#,
        r#"pamixer --get-mute"#,
    ));
    if Some("true".to_string()) == status {
        return Some("🔇".to_string());
    } else {
        if let Some(vol_str) = spawn(Some(
            // r#"amixer get Master | tail -n1 | sed -r "s/.*\[(.*)%\].*/\1/""#,
            r#"pamixer --get-volume"#,
        )){
            if let Ok(vol) = vol_str.parse::<u8>(){
                Some(if vol > 66 {
                    format!("🔊 {}%", vol)
                } else if vol > 33 {
                    format!("🔉 {}%", vol)
                } else {
                    format!("🔈 {}%", vol)
                })
            }else{
                None
            }
        }else{
            None
        }
    }
}

static mut NETBYTES:(u64,u64) = (0,0);

pub fn get_velocity_str(_: Option<&str>) -> Option<String> {
    if let Ok(netdev) = read_to_string("/proc/net/dev"){
        let new_bytes= netdev.lines().fold((0u64,0u64), |(r,t),line|{
            let mut spl = line.split_whitespace();
            if spl.next() == Some("lo:"){
                return (r,t);
            }else if let Some(rx) = spl.next() {
                if let Ok(rx) = rx.parse::<u64>(){
                    let mut spl = spl.skip(7);
                    if let Some(tx) = spl.next() {
                        if let Ok(tx) = tx.parse::<u64>(){
                            return (r+rx,t+tx);
                        }
                    }
                }
            }
            (r,t)
        });
        unsafe {
            let rv = (new_bytes.0-NETBYTES.0)>>10 / INTERVAL;
            let tv = (new_bytes.1-NETBYTES.1)>>10 / INTERVAL;
            NETBYTES = new_bytes;
            let rvs = if rv > 1024{
                format!("{}M/s",rv >> 10)
            }else{
                format!("{}K/s",rv)
            };
            let tvs = if tv > 1024{
                format!("{}M/s",tv >> 10)
            }else{
                format!("{}K/s",tv)
            };
            return Some(format!("⬇ {} ⬆ {}",rvs,tvs));
        };
    }else{
        None
    }
}

